'''
    model.py
    This file is part of:
    ActionCal - A Simple Calendar

    Copyright (C) 2006, 2007  R. P. Dillon

    This program is free software; you can redistribute it and/or modify
    it under the terms of version 2 the GNU General Public License as
    published by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
'''

from events import *

import os.path
import pickle
import calendar
import datetime

######################################################################
# Model
######################################################################

DEFAULT_SAVE_FILE="actioncal.dat"

# Set Sunday to be the first day of the week.
# TODO: Make this an option in the config file?
calendar.setfirstweekday(6)


class cal(object):
    """
    The model of the calendar we are using.
    """

    def __init__(self, saveFile=DEFAULT_SAVE_FILE):
        """
        Loads the calendar data from a save file, if available, otherwise
        generate new data for the calendar.
        """
        self.saveFile = saveFile
        if os.path.isfile(saveFile):
            f = open(self.saveFile, 'r')
            unpickler = pickle.Unpickler(f)
            self.events = unpickler.load()
            f.close()
        else:
            self.events = {}

    def saveData(self):
        f = open(self.saveFile, 'w')
        pickler = pickle.Pickler(f)
        pickler.dump(self.events)
        f.close()
        pass

    def setmanager(self, manager):
        self.manager = manager
        manager.register(self)

    def size(self):
        return len(self.events)

    ######################################################################
    # Calendar related methods - getting info about time periods
    def daysinmonth(self, date):
        """
        Get a list of the day numbers of the month in which the active
        date falls.
        """
        return range(1, calendar.monthrange(date.year, date.month)[1]+1)

    def weeksinmonth(self, date):
        """
        Returns the number of weeks over which the days in the active
        month are allocated.
        """
        return calendar.monthrange(date.year, date.month)[0]

    ######################################################################
    # Data methods

    def setdatetext(self, date, text):
        """
        Assigns the supplied text (a string, presumably) to the given
        date for later retrieval.
        """
        # If we are setting something to be the empty string and it
        # exists in your event map, remove it.
        if text == "":
            if date in self.events:
                del self.events[date]
        # If the text is empty and the date doesn't exist, we'll
        # just drop out of this method.
        # Otherwise, assign the text to the date
        else:
            self.events[date] = text

    def getdatetext(self, date):
        """
        Returns the text associated with the given date.

        If no text is associated, the empty string is returned.
        """
        if date in self.events:
            return self.events[date]
        return ""

    def handle(self, event):
        """
        Handles events from the manager.
        """
        if isinstance(event, setdaytextevent):
            self.setdatetext(event.date, event.text)
        elif isinstance(event, requestmonthdataevent):
            self.sendmonthdata(event.month)
        elif isinstance(event, persistdataevent):
            self.saveData()


    def sendmonthdata(self, date):
        """
        Sends the events in the requested month to the manager for
        posting to all listeners.

        The data is in the form of a dictionary that is keyed on the
        the date objects correspoinding to the dates in the requested
        month.
        """
        data  = {}
        for i in range(calendar.monthrange(date.year, date.month)[1]):
            tempdate = datetime.date(date.year, date.month, i+1)
            if tempdate in self.events:
                data[tempdate] = self.events[tempdate]
            else:
                data[tempdate] = ""
        e = monthdataevent(date, data)
        self.manager.post(e)        
